Trò chơi Angry Birds trong UNITY Engine
31.722 lượt xem;
1 using UnityEngine;
2 using System.Collections;
3 using System.Collections.Generic;
4
5
6 /// <summary>
7 /// base class for TweenChains and TweenFlows
8 /// </summary>
9 public class AbstractGoTweenCollection : AbstractGoTween
10 {
11 protected List<TweenFlowItem> _tweenFlows = new List<TweenFlowItem>();
12
13
14 /// <summary>
15 /// data class that wraps an AbstractTween and its start time for the timeline
16 /// </summary>
17 protected class TweenFlowItem
18 {
19 public float startTime;
20 public float endTime { get { return startTime + duration; } }
21 public float duration;
22 public AbstractGoTween tween;
23
24
25 public TweenFlowItem( float startTime, AbstractGoTween tween )
26 {
27 this.tween = tween;
28 this.startTime = startTime;
29 this.duration = tween.totalDuration;
30 }
31
32
33 public TweenFlowItem( float startTime, float duration )
34 {
35 this.duration = duration;
36 this.startTime = startTime;
37 }
38 }
39
40
41 public AbstractGoTweenCollection( GoTweenCollectionConfig config )
42 {
43 // allow events by default
44 allowEvents = true;
45
46 // setup callback bools
47 _didInit = false;
48 _didBegin = false;
49
50 // flag the onIterationStart event to fire.
51 // as long as goTo is not called on this tween, the onIterationStart event will fire
52 _fireIterationStart = true;
53
54 // copy the TweenConfig info over
55 id = config.id;
56 loopType = config.loopType;
57 iterations = config.iterations;
58 updateType = config.propertyUpdateType;
59 timeScale = 1;
60 state = GoTweenState.Paused;
61
62 _onInit = config.onInitHandler;
63 _onBegin = config.onBeginHandler;
64 _onIterationStart = config.onIterationStartHandler;
65 _onUpdate = config.onUpdateHandler;
66 _onIterationEnd = config.onIterationEndHandler;
67 _onComplete = config.onCompleteHandler;
68
69 Go.addTween( this );
70 }
71
72
73 #region AbstractTween overrides
74
75 /// <summary>
76 /// returns a list of all Tweens with the given target in the collection
77 /// technically, this should be marked as internal
78 /// </summary>
79 public List<GoTween> tweensWithTarget( object target )
80 {
81 List<GoTween> list = new List<GoTween>();
82
83 foreach( var flowItem in _tweenFlows )
84 {
85 // skip TweenFlowItems with no target
86 if( flowItem.tween == null )
87 continue;
88
89 // check Tweens first
90 var tween = flowItem.tween as GoTween;
91 if( tween != null && tween.target == target )
92 list.Add( tween );
93
94 // check for TweenCollections
95 if( tween == null )
96 {
97 var tweenCollection = flowItem.tween as AbstractGoTweenCollection;
98 if( tweenCollection != null )
99 {
100 var tweensInCollection = tweenCollection.tweensWithTarget( target );
101 if( tweensInCollection.Count > 0 )
102 list.AddRange( tweensInCollection );
103 }
104 }
105 }
106
107 return list;
108 }
109
110
111 public override bool removeTweenProperty( AbstractTweenProperty property )
112 {
113 foreach( var flowItem in _tweenFlows )
114 {
115 // skip delay items which have no tween
116 if( flowItem.tween == null )
117 continue;
118
119 if( flowItem.tween.removeTweenProperty( property ) )
120 return true;
121 }
122
123 return false;
124 }
125
126
127 public override bool containsTweenProperty( AbstractTweenProperty property )
128 {
129 foreach( var flowItem in _tweenFlows )
130 {
131 // skip delay items which have no tween
132 if( flowItem.tween == null )
133 continue;
134
135 if( flowItem.tween.containsTweenProperty( property ) )
136 return true;
137 }
138
139 return false;
140 }
141
142
143 public override List<AbstractTweenProperty> allTweenProperties()
144 {
145 var propList = new List<AbstractTweenProperty>();
146
147 foreach( var flowItem in _tweenFlows )
148 {
149 // skip delay items which have no tween
150 if( flowItem.tween == null )
151 continue;
152
153 propList.AddRange( flowItem.tween.allTweenProperties() );
154 }
155
156 return propList;
157 }
158
159
160 /// <summary>
161 /// we are always considered valid because our constructor adds us to Go and we start paused
162 /// </summary>
163 public override bool isValid()
164 {
165 return true;
166 }
167
168 /// <summary>
169 /// resumes playback
170 /// </summary>
171 public override void play()
172 {
173 base.play();
174
175 foreach( var flowItem in _tweenFlows )
176 {
177 if( flowItem.tween != null )
178 flowItem.tween.play();
179 }
180 }
181
182 /// <summary>
183 /// pauses playback
184 /// </summary>
185 public override void pause()
186 {
187 base.pause();
188
189 foreach( var flowItem in _tweenFlows )
190 {
191 if( flowItem.tween != null )
192 flowItem.tween.pause();
193 }
194 }
195
196 /// <summary>
197 /// tick method. if it returns true it indicates the tween is complete
198 /// </summary>
199 public override bool update( float deltaTime )
200 {
201 if ( !_didInit )
202 onInit();
203
204 if ( !_didBegin )
205 onBegin();
206
207 if ( _fireIterationStart )
208 onIterationStart();
209
210 // update the timeline and state.
211 base.update( deltaTime );
212
213 // get the proper elapsedTime if we're doing a PingPong
214 var convertedElapsedTime = _isLoopingBackOnPingPong ? duration - _elapsedTime : _elapsedTime;
215
216 // used for iterating over flowItems below.
217 TweenFlowItem flowItem = null;
218
219 // if we iterated last frame and this flow restarts from the beginning, we now need to reset all
220 // of the flowItem tweens to either the beginning or the end of their respective timelines
221 // we also want to do this in the _opposite_ way that we would normally iterate on them
222 // as the start value of a later flowItem may alter a property of an earlier flowItem.
223 if ( _didIterateLastFrame && loopType == GoLoopType.RestartFromBeginning )
224 {
225 if ( isReversed || _isLoopingBackOnPingPong )
226 {
227 for ( int i = 0; i < _tweenFlows.Count; ++i )
228 {
229 flowItem = _tweenFlows[i];
230
231 if ( flowItem.tween == null )
232 continue;
233
234 var cacheAllow = flowItem.tween.allowEvents;
235 flowItem.tween.allowEvents = false;
236 flowItem.tween.restart();
237 flowItem.tween.allowEvents = cacheAllow;
238 }
239 }
240 else
241 {
242 for ( int i = _tweenFlows.Count - 1; i >= 0; --i )
243 {
244 flowItem = _tweenFlows[i];
245
246 if ( flowItem.tween == null )
247 continue;
248
249 var cacheAllow = flowItem.tween.allowEvents;
250 flowItem.tween.allowEvents = false;
251 flowItem.tween.restart();
252 flowItem.tween.allowEvents = cacheAllow;
253 }
254 }
255 }
256 else
257 {
258 if ( ( isReversed && !_isLoopingBackOnPingPong ) || ( !isReversed && _isLoopingBackOnPingPong ) )
259 {
260 // if we are moving the tween in reverse, we should be iterating over the flowItems in reverse
261 // to help properties behave a bit better.
262 for ( var i = _tweenFlows.Count - 1; i >= 0; --i )
263 {
264 flowItem = _tweenFlows[i];
265
266 if ( flowItem.tween == null )
267 continue;
268
269 // if there's been an iteration this frame and we're not done yet, we want to make sure
270 // this tween is set to play in the right direction, and isn't set to complete/paused.
271 if ( _didIterateLastFrame && state != GoTweenState.Complete )
272 {
273 if ( !flowItem.tween.isReversed )
274 flowItem.tween.reverse();
275
276 flowItem.tween.play();
277 }
278
279 if ( flowItem.tween.state == GoTweenState.Running && flowItem.endTime >= convertedElapsedTime )
280 {
281 var convertedDeltaTime = Mathf.Abs( convertedElapsedTime - flowItem.startTime - flowItem.tween.totalElapsedTime );
282 flowItem.tween.update( convertedDeltaTime );
283 }
284 }
285 }
286 else
287 {
288 for ( int i = 0; i < _tweenFlows.Count; ++i )
289 {
290 flowItem = _tweenFlows[i];
291
292 if ( flowItem.tween == null )
293 continue;
294
295 // if there's been an iteration this frame and we're not done yet, we want to make sure
296 // this tween is set to play in the right direction, and isn't set to complete/paused.
297 if ( _didIterateLastFrame && state != GoTweenState.Complete )
298 {
299 if ( flowItem.tween.isReversed )
300 flowItem.tween.reverse();
301
302 flowItem.tween.play();
303 }
304
305 if ( flowItem.tween.state == GoTweenState.Running && flowItem.startTime <= convertedElapsedTime )
306 {
307 var convertedDeltaTime = convertedElapsedTime - flowItem.startTime - flowItem.tween.totalElapsedTime;
308 flowItem.tween.update( convertedDeltaTime );
309 }
310 }
311 }
312 }
313
314 onUpdate();
315
316 if ( _fireIterationEnd )
317 onIterationEnd();
318
319 if ( state == GoTweenState.Complete )
320 {
321 onComplete();
322
323 return true; // true if complete
324 }
325
326 return false; // false if not complete
327 }
328
329 /// <summary>
330 /// reverses playback. if going forward it will be going backward after this and vice versa.
331 /// </summary>
332 public override void reverse()
333 {
334 base.reverse();
335
336 var convertedElapsedTime = _isLoopingBackOnPingPong ? duration - _elapsedTime : _elapsedTime;
337
338 foreach ( var flowItem in _tweenFlows )
339 {
340 if ( flowItem.tween == null )
341 continue;
342
343 if ( isReversed != flowItem.tween.isReversed )
344 flowItem.tween.reverse();
345
346 flowItem.tween.pause();
347
348 // we selectively mark tweens for play if they will be played immediately or in the future.
349 // update() will filter out more tweens that should not be played yet.
350 if ( isReversed || _isLoopingBackOnPingPong )
351 {
352 if ( flowItem.startTime <= convertedElapsedTime )
353 flowItem.tween.play();
354 }
355 else
356 {
357 if ( flowItem.endTime >= convertedElapsedTime )
358 flowItem.tween.play();
359 }
360 }
361 }
362
363 /// <summary>
364 /// goes to the specified time clamping it from 0 to the total duration of the tween. if the tween is
365 /// not playing it will be force updated to the time specified.
366 /// </summary>
367 public override void goTo( float time, bool skipDelay = true )
368 {
369 time = Mathf.Clamp( time, 0f, totalDuration );
370
371 // provide an early out for calling goTo on the same time multiple times.
372 if ( time == _totalElapsedTime )
373 return;
374
375 // we don't simply call base.goTo because that would force an update within AbstractGoTweenCollection,
376 // which forces an update on all the tweenFlowItems without putting them in the right position.
377 // it's also possible that people will move around a tween via the goTo method, so we want to
378 // try to make that as efficient as possible.
379
380 // if we are doing a goTo at the "start" of the timeline, based on the isReversed variable,
381 // allow the onBegin and onIterationStart callback to fire again.
382 // we only allow the onIterationStart event callback to fire at the start of the timeline,
383 // as doing a goTo(x) where x % duration == 0 will trigger the onIterationEnd before we
384 // go to the start.
385 if ( ( isReversed && time == totalDuration ) || ( !isReversed && time == 0f ) )
386 {
387 _didBegin = false;
388 _fireIterationStart = true;
389 }
390 else
391 {
392 _didBegin = true;
393 _fireIterationStart = false;
394 }
395
396 // since we're doing a goTo, we want to stop this tween from remembering that it iterated.
397 // this could cause issues if you caused the tween to complete an iteration and then goTo somewhere
398 // else while still paused.
399 _didIterateThisFrame = false;
400
401 // force a time and completedIterations before we update
402 _totalElapsedTime = time;
403 _completedIterations = isReversed ? Mathf.CeilToInt( _totalElapsedTime / duration ) : Mathf.FloorToInt( _totalElapsedTime / duration );
404
405 // we don't want to use the Collection update function, because we don't have all of our
406 // child tweenFlowItems setup properly. this will properly setup our iterations,
407 // totalElapsedTime, and other useful information.
408 base.update( 0 );
409
410 var convertedElapsedTime = _isLoopingBackOnPingPong ? duration - _elapsedTime : _elapsedTime;
411
412 // we always want to process items in the future of this tween from last to first.
413 // and items that have already occured from first to last.
414 TweenFlowItem flowItem = null;
415 if ( isReversed || _isLoopingBackOnPingPong )
416 {
417 // flowItems in the future of the timeline
418 for ( int i = 0; i < _tweenFlows.Count; ++i )
419 {
420 flowItem = _tweenFlows[i];
421
422 if ( flowItem == null )
423 continue;
424
425 if ( flowItem.endTime >= convertedElapsedTime )
426 break;
427
428 changeTimeForFlowItem( flowItem, convertedElapsedTime );
429 }
430
431 // flowItems in the past & current part of the timeline
432 for ( int i = _tweenFlows.Count - 1; i >= 0; --i )
433 {
434 flowItem = _tweenFlows[i];
435
436 if ( flowItem == null )
437 continue;
438
439 if ( flowItem.endTime < convertedElapsedTime )
440 break;
441
442 changeTimeForFlowItem( flowItem, convertedElapsedTime );
443 }
444 }
445 else
446 {
447 // flowItems in the future of the timeline
448 for ( int i = _tweenFlows.Count - 1; i >= 0; --i )
449 {
450 flowItem = _tweenFlows[i];
451
452 if ( flowItem == null )
453 continue;
454
455 if ( flowItem.startTime <= convertedElapsedTime )
456 break;
457
458 changeTimeForFlowItem( flowItem, convertedElapsedTime );
459 }
460
461 // flowItems in the past & current part of the timeline
462 for ( int i = 0; i < _tweenFlows.Count; ++i )
463 {
464 flowItem = _tweenFlows[i];
465
466 if ( flowItem == null )
467 continue;
468
469 if ( flowItem.startTime > convertedElapsedTime )
470 break;
471
472 changeTimeForFlowItem( flowItem, convertedElapsedTime );
473 }
474 }
475 }
476
477 private void changeTimeForFlowItem( TweenFlowItem flowItem, float time )
478 {
479 if ( flowItem == null || flowItem.tween == null )
480 return;
481
482 if ( flowItem.tween.isReversed != ( isReversed || _isLoopingBackOnPingPong ) )
483 flowItem.tween.reverse();
484
485 var convertedTime = Mathf.Clamp( time - flowItem.startTime, 0f, flowItem.endTime );
486
487 if ( flowItem.startTime <= time && flowItem.endTime >= time )
488 {
489 flowItem.tween.goToAndPlay( convertedTime );
490 }
491 else
492 {
493 flowItem.tween.goTo( convertedTime );
494 flowItem.tween.pause();
495 }
496 }
497
498 #endregion
499
500 }
2 using System.Collections;
3 using System.Collections.Generic;
4
5
6 /// <summary>
7 /// base class for TweenChains and TweenFlows
8 /// </summary>
9 public class AbstractGoTweenCollection : AbstractGoTween
10 {
11 protected List<TweenFlowItem> _tweenFlows = new List<TweenFlowItem>();
12
13
14 /// <summary>
15 /// data class that wraps an AbstractTween and its start time for the timeline
16 /// </summary>
17 protected class TweenFlowItem
18 {
19 public float startTime;
20 public float endTime { get { return startTime + duration; } }
21 public float duration;
22 public AbstractGoTween tween;
23
24
25 public TweenFlowItem( float startTime, AbstractGoTween tween )
26 {
27 this.tween = tween;
28 this.startTime = startTime;
29 this.duration = tween.totalDuration;
30 }
31
32
33 public TweenFlowItem( float startTime, float duration )
34 {
35 this.duration = duration;
36 this.startTime = startTime;
37 }
38 }
39
40
41 public AbstractGoTweenCollection( GoTweenCollectionConfig config )
42 {
43 // allow events by default
44 allowEvents = true;
45
46 // setup callback bools
47 _didInit = false;
48 _didBegin = false;
49
50 // flag the onIterationStart event to fire.
51 // as long as goTo is not called on this tween, the onIterationStart event will fire
52 _fireIterationStart = true;
53
54 // copy the TweenConfig info over
55 id = config.id;
56 loopType = config.loopType;
57 iterations = config.iterations;
58 updateType = config.propertyUpdateType;
59 timeScale = 1;
60 state = GoTweenState.Paused;
61
62 _onInit = config.onInitHandler;
63 _onBegin = config.onBeginHandler;
64 _onIterationStart = config.onIterationStartHandler;
65 _onUpdate = config.onUpdateHandler;
66 _onIterationEnd = config.onIterationEndHandler;
67 _onComplete = config.onCompleteHandler;
68
69 Go.addTween( this );
70 }
71
72
73 #region AbstractTween overrides
74
75 /// <summary>
76 /// returns a list of all Tweens with the given target in the collection
77 /// technically, this should be marked as internal
78 /// </summary>
79 public List<GoTween> tweensWithTarget( object target )
80 {
81 List<GoTween> list = new List<GoTween>();
82
83 foreach( var flowItem in _tweenFlows )
84 {
85 // skip TweenFlowItems with no target
86 if( flowItem.tween == null )
87 continue;
88
89 // check Tweens first
90 var tween = flowItem.tween as GoTween;
91 if( tween != null && tween.target == target )
92 list.Add( tween );
93
94 // check for TweenCollections
95 if( tween == null )
96 {
97 var tweenCollection = flowItem.tween as AbstractGoTweenCollection;
98 if( tweenCollection != null )
99 {
100 var tweensInCollection = tweenCollection.tweensWithTarget( target );
101 if( tweensInCollection.Count > 0 )
102 list.AddRange( tweensInCollection );
103 }
104 }
105 }
106
107 return list;
108 }
109
110
111 public override bool removeTweenProperty( AbstractTweenProperty property )
112 {
113 foreach( var flowItem in _tweenFlows )
114 {
115 // skip delay items which have no tween
116 if( flowItem.tween == null )
117 continue;
118
119 if( flowItem.tween.removeTweenProperty( property ) )
120 return true;
121 }
122
123 return false;
124 }
125
126
127 public override bool containsTweenProperty( AbstractTweenProperty property )
128 {
129 foreach( var flowItem in _tweenFlows )
130 {
131 // skip delay items which have no tween
132 if( flowItem.tween == null )
133 continue;
134
135 if( flowItem.tween.containsTweenProperty( property ) )
136 return true;
137 }
138
139 return false;
140 }
141
142
143 public override List<AbstractTweenProperty> allTweenProperties()
144 {
145 var propList = new List<AbstractTweenProperty>();
146
147 foreach( var flowItem in _tweenFlows )
148 {
149 // skip delay items which have no tween
150 if( flowItem.tween == null )
151 continue;
152
153 propList.AddRange( flowItem.tween.allTweenProperties() );
154 }
155
156 return propList;
157 }
158
159
160 /// <summary>
161 /// we are always considered valid because our constructor adds us to Go and we start paused
162 /// </summary>
163 public override bool isValid()
164 {
165 return true;
166 }
167
168 /// <summary>
169 /// resumes playback
170 /// </summary>
171 public override void play()
172 {
173 base.play();
174
175 foreach( var flowItem in _tweenFlows )
176 {
177 if( flowItem.tween != null )
178 flowItem.tween.play();
179 }
180 }
181
182 /// <summary>
183 /// pauses playback
184 /// </summary>
185 public override void pause()
186 {
187 base.pause();
188
189 foreach( var flowItem in _tweenFlows )
190 {
191 if( flowItem.tween != null )
192 flowItem.tween.pause();
193 }
194 }
195
196 /// <summary>
197 /// tick method. if it returns true it indicates the tween is complete
198 /// </summary>
199 public override bool update( float deltaTime )
200 {
201 if ( !_didInit )
202 onInit();
203
204 if ( !_didBegin )
205 onBegin();
206
207 if ( _fireIterationStart )
208 onIterationStart();
209
210 // update the timeline and state.
211 base.update( deltaTime );
212
213 // get the proper elapsedTime if we're doing a PingPong
214 var convertedElapsedTime = _isLoopingBackOnPingPong ? duration - _elapsedTime : _elapsedTime;
215
216 // used for iterating over flowItems below.
217 TweenFlowItem flowItem = null;
218
219 // if we iterated last frame and this flow restarts from the beginning, we now need to reset all
220 // of the flowItem tweens to either the beginning or the end of their respective timelines
221 // we also want to do this in the _opposite_ way that we would normally iterate on them
222 // as the start value of a later flowItem may alter a property of an earlier flowItem.
223 if ( _didIterateLastFrame && loopType == GoLoopType.RestartFromBeginning )
224 {
225 if ( isReversed || _isLoopingBackOnPingPong )
226 {
227 for ( int i = 0; i < _tweenFlows.Count; ++i )
228 {
229 flowItem = _tweenFlows[i];
230
231 if ( flowItem.tween == null )
232 continue;
233
234 var cacheAllow = flowItem.tween.allowEvents;
235 flowItem.tween.allowEvents = false;
236 flowItem.tween.restart();
237 flowItem.tween.allowEvents = cacheAllow;
238 }
239 }
240 else
241 {
242 for ( int i = _tweenFlows.Count - 1; i >= 0; --i )
243 {
244 flowItem = _tweenFlows[i];
245
246 if ( flowItem.tween == null )
247 continue;
248
249 var cacheAllow = flowItem.tween.allowEvents;
250 flowItem.tween.allowEvents = false;
251 flowItem.tween.restart();
252 flowItem.tween.allowEvents = cacheAllow;
253 }
254 }
255 }
256 else
257 {
258 if ( ( isReversed && !_isLoopingBackOnPingPong ) || ( !isReversed && _isLoopingBackOnPingPong ) )
259 {
260 // if we are moving the tween in reverse, we should be iterating over the flowItems in reverse
261 // to help properties behave a bit better.
262 for ( var i = _tweenFlows.Count - 1; i >= 0; --i )
263 {
264 flowItem = _tweenFlows[i];
265
266 if ( flowItem.tween == null )
267 continue;
268
269 // if there's been an iteration this frame and we're not done yet, we want to make sure
270 // this tween is set to play in the right direction, and isn't set to complete/paused.
271 if ( _didIterateLastFrame && state != GoTweenState.Complete )
272 {
273 if ( !flowItem.tween.isReversed )
274 flowItem.tween.reverse();
275
276 flowItem.tween.play();
277 }
278
279 if ( flowItem.tween.state == GoTweenState.Running && flowItem.endTime >= convertedElapsedTime )
280 {
281 var convertedDeltaTime = Mathf.Abs( convertedElapsedTime - flowItem.startTime - flowItem.tween.totalElapsedTime );
282 flowItem.tween.update( convertedDeltaTime );
283 }
284 }
285 }
286 else
287 {
288 for ( int i = 0; i < _tweenFlows.Count; ++i )
289 {
290 flowItem = _tweenFlows[i];
291
292 if ( flowItem.tween == null )
293 continue;
294
295 // if there's been an iteration this frame and we're not done yet, we want to make sure
296 // this tween is set to play in the right direction, and isn't set to complete/paused.
297 if ( _didIterateLastFrame && state != GoTweenState.Complete )
298 {
299 if ( flowItem.tween.isReversed )
300 flowItem.tween.reverse();
301
302 flowItem.tween.play();
303 }
304
305 if ( flowItem.tween.state == GoTweenState.Running && flowItem.startTime <= convertedElapsedTime )
306 {
307 var convertedDeltaTime = convertedElapsedTime - flowItem.startTime - flowItem.tween.totalElapsedTime;
308 flowItem.tween.update( convertedDeltaTime );
309 }
310 }
311 }
312 }
313
314 onUpdate();
315
316 if ( _fireIterationEnd )
317 onIterationEnd();
318
319 if ( state == GoTweenState.Complete )
320 {
321 onComplete();
322
323 return true; // true if complete
324 }
325
326 return false; // false if not complete
327 }
328
329 /// <summary>
330 /// reverses playback. if going forward it will be going backward after this and vice versa.
331 /// </summary>
332 public override void reverse()
333 {
334 base.reverse();
335
336 var convertedElapsedTime = _isLoopingBackOnPingPong ? duration - _elapsedTime : _elapsedTime;
337
338 foreach ( var flowItem in _tweenFlows )
339 {
340 if ( flowItem.tween == null )
341 continue;
342
343 if ( isReversed != flowItem.tween.isReversed )
344 flowItem.tween.reverse();
345
346 flowItem.tween.pause();
347
348 // we selectively mark tweens for play if they will be played immediately or in the future.
349 // update() will filter out more tweens that should not be played yet.
350 if ( isReversed || _isLoopingBackOnPingPong )
351 {
352 if ( flowItem.startTime <= convertedElapsedTime )
353 flowItem.tween.play();
354 }
355 else
356 {
357 if ( flowItem.endTime >= convertedElapsedTime )
358 flowItem.tween.play();
359 }
360 }
361 }
362
363 /// <summary>
364 /// goes to the specified time clamping it from 0 to the total duration of the tween. if the tween is
365 /// not playing it will be force updated to the time specified.
366 /// </summary>
367 public override void goTo( float time, bool skipDelay = true )
368 {
369 time = Mathf.Clamp( time, 0f, totalDuration );
370
371 // provide an early out for calling goTo on the same time multiple times.
372 if ( time == _totalElapsedTime )
373 return;
374
375 // we don't simply call base.goTo because that would force an update within AbstractGoTweenCollection,
376 // which forces an update on all the tweenFlowItems without putting them in the right position.
377 // it's also possible that people will move around a tween via the goTo method, so we want to
378 // try to make that as efficient as possible.
379
380 // if we are doing a goTo at the "start" of the timeline, based on the isReversed variable,
381 // allow the onBegin and onIterationStart callback to fire again.
382 // we only allow the onIterationStart event callback to fire at the start of the timeline,
383 // as doing a goTo(x) where x % duration == 0 will trigger the onIterationEnd before we
384 // go to the start.
385 if ( ( isReversed && time == totalDuration ) || ( !isReversed && time == 0f ) )
386 {
387 _didBegin = false;
388 _fireIterationStart = true;
389 }
390 else
391 {
392 _didBegin = true;
393 _fireIterationStart = false;
394 }
395
396 // since we're doing a goTo, we want to stop this tween from remembering that it iterated.
397 // this could cause issues if you caused the tween to complete an iteration and then goTo somewhere
398 // else while still paused.
399 _didIterateThisFrame = false;
400
401 // force a time and completedIterations before we update
402 _totalElapsedTime = time;
403 _completedIterations = isReversed ? Mathf.CeilToInt( _totalElapsedTime / duration ) : Mathf.FloorToInt( _totalElapsedTime / duration );
404
405 // we don't want to use the Collection update function, because we don't have all of our
406 // child tweenFlowItems setup properly. this will properly setup our iterations,
407 // totalElapsedTime, and other useful information.
408 base.update( 0 );
409
410 var convertedElapsedTime = _isLoopingBackOnPingPong ? duration - _elapsedTime : _elapsedTime;
411
412 // we always want to process items in the future of this tween from last to first.
413 // and items that have already occured from first to last.
414 TweenFlowItem flowItem = null;
415 if ( isReversed || _isLoopingBackOnPingPong )
416 {
417 // flowItems in the future of the timeline
418 for ( int i = 0; i < _tweenFlows.Count; ++i )
419 {
420 flowItem = _tweenFlows[i];
421
422 if ( flowItem == null )
423 continue;
424
425 if ( flowItem.endTime >= convertedElapsedTime )
426 break;
427
428 changeTimeForFlowItem( flowItem, convertedElapsedTime );
429 }
430
431 // flowItems in the past & current part of the timeline
432 for ( int i = _tweenFlows.Count - 1; i >= 0; --i )
433 {
434 flowItem = _tweenFlows[i];
435
436 if ( flowItem == null )
437 continue;
438
439 if ( flowItem.endTime < convertedElapsedTime )
440 break;
441
442 changeTimeForFlowItem( flowItem, convertedElapsedTime );
443 }
444 }
445 else
446 {
447 // flowItems in the future of the timeline
448 for ( int i = _tweenFlows.Count - 1; i >= 0; --i )
449 {
450 flowItem = _tweenFlows[i];
451
452 if ( flowItem == null )
453 continue;
454
455 if ( flowItem.startTime <= convertedElapsedTime )
456 break;
457
458 changeTimeForFlowItem( flowItem, convertedElapsedTime );
459 }
460
461 // flowItems in the past & current part of the timeline
462 for ( int i = 0; i < _tweenFlows.Count; ++i )
463 {
464 flowItem = _tweenFlows[i];
465
466 if ( flowItem == null )
467 continue;
468
469 if ( flowItem.startTime > convertedElapsedTime )
470 break;
471
472 changeTimeForFlowItem( flowItem, convertedElapsedTime );
473 }
474 }
475 }
476
477 private void changeTimeForFlowItem( TweenFlowItem flowItem, float time )
478 {
479 if ( flowItem == null || flowItem.tween == null )
480 return;
481
482 if ( flowItem.tween.isReversed != ( isReversed || _isLoopingBackOnPingPong ) )
483 flowItem.tween.reverse();
484
485 var convertedTime = Mathf.Clamp( time - flowItem.startTime, 0f, flowItem.endTime );
486
487 if ( flowItem.startTime <= time && flowItem.endTime >= time )
488 {
489 flowItem.tween.goToAndPlay( convertedTime );
490 }
491 else
492 {
493 flowItem.tween.goTo( convertedTime );
494 flowItem.tween.pause();
495 }
496 }
497
498 #endregion
499
500 }